package com.lambo.maven.core.utils.superHttp.utils;

import java.io.IOException;
import java.net.Authenticator;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.PasswordAuthentication;
import java.net.Proxy;
import java.net.Socket;
import java.net.UnknownHostException;

import javax.net.ssl.SSLContext;

import org.apache.http.HttpHost;
import org.apache.http.client.protocol.HttpClientContext;
import org.apache.http.config.Registry;
import org.apache.http.config.RegistryBuilder;
import org.apache.http.conn.DnsResolver;
import org.apache.http.conn.socket.ConnectionSocketFactory;
import org.apache.http.conn.socket.PlainConnectionSocketFactory;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.protocol.HttpContext;
import org.apache.http.ssl.SSLContexts;

/**
 * sock5代理工具类
 * Sock5Util
 */
public class Sock5Util {

    public static CloseableHttpClient getHttpClient() {
        return getHttpClient(null);
    }

    public static CloseableHttpClient getHttpClient(SSLConnectionSocketFactory ssfsl) {

        // String proxyHost = "192.168.43.1";
        // int proxyPort = 1080;
        final String proxyName = "";
        final String proxyPwd = "";
        
        Authenticator.setDefault(new Authenticator(){
            protected  PasswordAuthentication  getPasswordAuthentication(){
                PasswordAuthentication p=new PasswordAuthentication(proxyName, proxyPwd.toCharArray());
                return p;
            }
        });

        if(ssfsl == null) {
            ssfsl = new MySSLConnectionSocketFactory(SSLContexts.createSystemDefault());
        }

        RegistryBuilder<ConnectionSocketFactory> register = RegistryBuilder.<ConnectionSocketFactory> create();
        Registry<ConnectionSocketFactory> reg = register
                .register("http", new MyConnectionSocketFactory())
                .register("https", ssfsl).build();
        
        PoolingHttpClientConnectionManager cm = new PoolingHttpClientConnectionManager(reg, new FakeDnsResolver());

        CloseableHttpClient httpclient = HttpClients.custom().setConnectionManager(cm).build();
        return httpclient;
    }

    /**
     * sock5代理设置
     * @param host 代理ip或域名
     * @param port 代理端口
     * @return
     */
    public static HttpClientContext getSock5Context(String host, int port) {
        InetSocketAddress socksaddr = new InetSocketAddress(host, port);
        HttpClientContext context = HttpClientContext.create();
        context.setAttribute("socks.address", socksaddr);
        return context;
    }

    static class FakeDnsResolver implements DnsResolver {
        @Override
        public InetAddress[] resolve(String host) throws UnknownHostException {
            // Return some fake DNS record for every request, we won't be using it
            return new InetAddress[] { InetAddress.getByAddress(new byte[] { 1, 1, 1, 1 }) };
        }
    }
 
    static class MyConnectionSocketFactory extends PlainConnectionSocketFactory {
        @Override
        public Socket createSocket(final HttpContext context) throws IOException {
            InetSocketAddress socksaddr = (InetSocketAddress) context.getAttribute("socks.address");
            Proxy proxy = new Proxy(Proxy.Type.SOCKS, socksaddr);
            return new Socket(proxy);
        }
 
        @Override
        public Socket connectSocket(int connectTimeout, Socket socket, HttpHost host, InetSocketAddress remoteAddress,
                                    InetSocketAddress localAddress, HttpContext context) throws IOException {
            // Convert address to unresolved
            InetSocketAddress unresolvedRemote = InetSocketAddress
                    .createUnresolved(host.getHostName(), remoteAddress.getPort());
            return super.connectSocket(connectTimeout, socket, host, unresolvedRemote, localAddress, context);
        }
    }
 
    static class MySSLConnectionSocketFactory extends SSLConnectionSocketFactory {
 
        public MySSLConnectionSocketFactory(final SSLContext sslContext) {
         
            super(sslContext, ALLOW_ALL_HOSTNAME_VERIFIER);
        }
 
        @Override
        public Socket createSocket(final HttpContext context) throws IOException {
            InetSocketAddress socksaddr = (InetSocketAddress) context.getAttribute("socks.address");
            Proxy proxy = new Proxy(Proxy.Type.SOCKS, socksaddr);
            return new Socket(proxy);
        }
 
        @Override
        public Socket connectSocket(int connectTimeout, Socket socket, HttpHost host, InetSocketAddress remoteAddress,
                                    InetSocketAddress localAddress, HttpContext context) throws IOException {
            // Convert address to unresolved
            InetSocketAddress unresolvedRemote = InetSocketAddress
                    .createUnresolved(host.getHostName(), remoteAddress.getPort());
            return super.connectSocket(connectTimeout, socket, host, unresolvedRemote, localAddress, context);
        }
    }


}